package main;

import java.awt.Button;
import java.awt.Component;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
import java.util.ArrayList;

import terrain.LowWallRect;
import terrain.Terrain;
import equipment.*;
//import main.*;

public class Unit {
	public Game game;
	public Army army;
	public Equipment[] equipChoices = {};
	
	// Game attributes
	protected int strength;
	protected int defense;
	protected int attacks;
	protected int wounds;
	protected int courage;
	protected int fightValue;
	protected int shootValue;
	
	public int workingStrength;
	public int workingDefense;
	public int workingAttacks;
	public int workingWounds;
	public int workingCourage;
	public int workingFightValue;
	public int workingShootValue;
	
	
	
	public int might = 0;
	public int will = 0;
	public int fate = 0;
	public int mightLeft = 0;
	public int willLeft = 0;
	public int fateLeft = 0;
	
	public double baseMove;
	public double move;
	public double moveLeft;
	public int shootRange = 0;
	public int shootStrength = 2;
	public double moveNeededToShoot = 0.5;
	public boolean hasShot = false;
	public boolean hasFought = false;
	
	public boolean passedChargeTest = false;
	public boolean passedBrokenTest = false;
	
	public boolean hasUsedMagic = false;
	public ArrayList<String> spellList = new ArrayList<String>();
	
	protected boolean isTerrifying = false;
	protected boolean tempTerrifying = isTerrifying;
	
	public boolean layingDown = false;
	public boolean isTransfixed = false;
	
	public ArrayList<Button> refreshButtons = new ArrayList<Button>();
	
	// Individual attributes
	public int id;
	public String name;
	public String race = "";
	public int x;
	public int y;
	public int armyIndex;
	public ArrayList<Equipment> equipmentList = new ArrayList<Equipment>();
	public double inchRadius = 0.5;
	public int pixelRadius = 15;
	
	// Battle attributes	
	public Battle battle = null;
	protected int battleDice;
	protected int battleBonus;
	protected int woundDice;
	protected int woundBonus;
	public boolean hasRetreated = true;
	
	public Unit supporting = null;
	public ArrayList<Unit> supporters = new ArrayList<Unit>();
	
	public ArrayList<Unit> unitsContacted = new ArrayList<Unit>();
	public ArrayList<Terrain> terrainContacted = new ArrayList<Terrain>();

	public static Random rng = new Random();
	
	public Unit() {
	}
	
	public void initWorking() {
		this.workingStrength = this.strength;
		this.workingDefense = this.defense;
		this.workingAttacks = this.attacks;
		this.workingWounds = this.wounds;
		this.workingCourage = this.courage;
		this.workingFightValue = this.fightValue;
		this.workingShootValue = this.shootValue;
		this.mightLeft = this.might;
		this.willLeft = this.will;
		this.fateLeft = this.fate;
	}
	
	public Unit clone() {
		return new Unit();
	}
	
	public void equip(Equipment e) {
		e.equipTo(this);
		this.equipmentList.add(e);
	}

	public Equipment[] getEquipChoices() {
		return this.equipChoices;
	}
	
	public boolean hasEquipment(Equipment e) {
		for (Equipment myE : equipmentList) {
			if (myE.getClass() == e.getClass())
				return true;
		}
		return false;
	}
	
	public void attackMove(int destX, int destY) {
		if (this.moveLeft == 0)
			return;
		else if (this.isTransfixed) {
			UI.messageLog.add(this.toChoiceString() + " is transfixed/immobilized!");
			return;
		}
		if (destX < 0 || destX > game.board.pixelWidth 
				|| destY < 0 || destY > game.board.pixelHeight)
			return;
		
		// Check if the force is broken (below half strength), and if so we need to take a courage test to move
		if (this.army.units.size() < this.army.origSize/2 && !this.passedBrokenTest) {
			Button doneTesting = new Button();
			doneTesting.addMouseListener(new MouseListener(){
				public void mouseClicked(MouseEvent arg0) {
					if (!passedBrokenTest) {
						// Failed to pass broken army test, flee the battlefield
						die();
						game.myUI.selectedUnit = null;
					}
					else {
						// Passed the courage test, move normally (passedBrokenTest should be true, so we skip the check on the recursion)
						attackMove(destX, destY);
					}
				}
				public void mouseEntered(MouseEvent arg0) {}
				public void mouseExited(MouseEvent arg0) {}
				public void mousePressed(MouseEvent arg0) {}
				public void mouseReleased(MouseEvent arg0) {}
			});
			this.takeCourageTest(doneTesting, "Broken");
		}
		
		int rootX = this.x;
		int rootY = this.y;
		int newX = destX;
		int newY = destY;
		double shortDist = Utils.inchDist(rootX, rootY, newX, newY);
		Unit closeUnit = null;
		
		for(Army a : game.armies){
			for(Unit u : a.units) {
				if (u.id != this.id){
					Point2D p = Utils.findContactPoint(this, u, destX, destY);
					
					if (p == null)
						continue;
					
					double x = Utils.inchDist(rootX, rootY, (int)p.getX(), (int)p.getY());
					if (x < shortDist) {
						newX = (int)p.getX();
						newY = (int)p.getY();
						shortDist = x;
						closeUnit = u;
					}
					
				}
			}
		}
		
		Point2D closeTerrainPt = null;
		Point2D candidate;
		Terrain closeTerrain = null;
		for (Terrain t : game.board.terrainList) {
			candidate = t.contactPoint(rootX, rootY, destX, destY, this.pixelRadius);
			if (candidate != null) {
				System.out.println("CANDIDATE POINT: " + candidate.getX() + " " + candidate.getY());
			}
			if (candidate != null && (closeTerrainPt == null || 
					candidate.distance(rootX, rootY) < closeTerrainPt.distance(rootX, rootY))){
				closeTerrainPt = (Point2D)candidate.clone();
				closeTerrain = t;
			}
		}
		
		
		/* Strategy for control zones:
		 * 		if closeUnit exists
		 * 			make a rect+halfcircle to newX, newY pulled back by an inch (point we enter control zone)
		 * 		otherwise
		 * 			make rect+halfcircle with newX, newY
		 * 		check if that area intersects with any other control zones
		 * 		if so, no good
		 * 
		 * 		actually, need to also check if we're going to a terrain point
		 */
		Area walkPath = new Area();
		int controlX = rootX;
		int controlY = rootY;
		
		boolean inTargetControlZone = false;
		
		if (closeTerrainPt != null && closeTerrainPt.getX() != -1 &&
				Utils.inchDist(rootX, rootY, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY()) <= this.moveLeft
				&& (closeUnit == null || (closeUnit != null && closeTerrainPt.distance(rootX, rootY) < Utils.pixelDist(rootX, rootY, newX, newY)))){
			controlX = (int)closeTerrainPt.getX();
			controlY = (int)closeTerrainPt.getY();
			//System.out.println("Moving to terrain Point" + controlX + " " + controlY);
		}
		else if (closeUnit != null && closeUnit.armyIndex != this.armyIndex
					&& Utils.inchDist(rootX, rootY, newX, newY) <= this.moveLeft) {
			// Check if we're starting inside the eventual target's control zone
			if (Utils.pixelDist(closeUnit.x, closeUnit.y, rootX, rootY) <= this.pixelRadius + closeUnit.pixelRadius + Utils.pixelsPerInch)
				inTargetControlZone = true;
			// Scale back by entry to closeUnit's control zone
			double theta = Math.abs(Math.atan2(closeUnit.y-rootY, closeUnit.x-rootX) -
					Math.atan2(destY-rootY, destX-rootX));
			// Use law of cosines with triangle created by (root, closeUnit, enterControlZone) (wikipedia)
			double c = closeUnit.pixelRadius + this.pixelRadius + Utils.pixelsPerInch;
			double b = Utils.pixelDist(this, closeUnit);
			double distToControl = b * Math.cos(theta) - Math.sqrt(c*c - b*b*Math.sin(theta)*Math.sin(theta));
			double ratio = distToControl / Utils.pixelDist(rootX, rootY, newX, newY);
			
			controlX = (int)(rootX + ratio*(newX-rootX));
			controlY = (int)(rootY + ratio*(newY-rootY));
			//System.out.println("Moving to unit Point" + controlX + " " + controlY);
		}
		else if (Utils.inchDist(rootX, rootY, newX, newY) <= this.moveLeft) {
			controlX = newX;
			controlY = newY;
			//System.out.println("Moving to Point" + controlX + " " + controlY);
		}
		else // Too far, no movement
			return;
		
		
		
		// Only need to check if we aren't already inside our target's control zone
		if (!inTargetControlZone) {
			// Build the walk path with controlX and controlY
			double distToControl = Math.sqrt(Math.pow(rootX-controlX, 2) + Math.pow(rootY-controlY, 2));
			walkPath = new Area(new Rectangle2D.Double(rootX, rootY-this.pixelRadius, distToControl, 2*this.pixelRadius));
			double theta = Math.atan2(controlY-rootY, controlX-rootX);
			AffineTransform rotate = AffineTransform.getRotateInstance(theta, rootX, rootY);
			walkPath.transform(rotate);
			
			walkPath.add(new Area(new Ellipse2D.Double(controlX-this.pixelRadius, controlY-this.pixelRadius, 
									2*this.pixelRadius, 2*this.pixelRadius)));
			//((MoveUI)game.myUI.phaseUI).walkPath = walkPath;
			
			ArrayList<Unit> enemyUnits = new ArrayList<Unit>();
			if (this.armyIndex == Game.GOODINDEX)
				enemyUnits = this.game.armies[Game.BADINDEX].units;
			else if (this.armyIndex == Game.BADINDEX)
				enemyUnits = this.game.armies[Game.GOODINDEX].units;
			for (Unit enemy : enemyUnits){
				if (closeUnit != null && enemy.id == closeUnit.id)
					continue;
				Area enemyControlZone = enemy.getControlZone();
				enemyControlZone.intersect(walkPath);
				if (!enemyControlZone.isEmpty()) {
					// Check for barrier between us and enemy
					boolean isBlocked = false;
					for (Terrain t : game.board.terrainList) {
						if (t.isObstacle) {
							Area connectLine = new Area(new Line2D.Double(this.x, this.y, enemy.x, enemy.y));
							connectLine.intersect(t.obstacle);
							Rectangle2D rect = connectLine.getBounds2D();
							if (rect.getWidth() > 0 || rect.getHeight() > 0) {
								isBlocked = true;
								break;
							}
						}
					}
					// Check for moving away from the unit
					boolean movingAway = false;
					double theta2 = Math.abs(Math.atan2(enemy.y-rootY, enemy.x-rootX) -
							Math.atan2(newY-rootY, newX-rootX));
					movingAway = theta2 > Math.PI/2;
					if (!isBlocked && !movingAway){
						System.out.println("enemy: " + enemy.toChoiceString());
						((MoveUI)game.myUI.phaseUI).walkPath = walkPath;
						UI.messageLog.add("Can't enter a unit's control zone without charging it! (" + enemy.toChoiceString() + ")");
						return;
					}
				}
			}
		}
		
		
		
		
		
		
		//System.out.println("CHECKED ALL TERRAIN: " + closeTerrainPt.getX() + " " + closeTerrainPt.getY());
		// If nearest terrain is closer than closest unit, move there
		if (closeTerrainPt != null && closeTerrainPt.getX() != -1 &&
				Utils.inchDist(rootX, rootY, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY()) <= this.moveLeft
				&& (closeUnit == null || (closeUnit != null && closeTerrainPt.distance(rootX, rootY) < Utils.pixelDist(rootX, rootY, newX, newY)))){
			this.uncontactTerrain();
			this.uncontactUnits();
			this.x = (int)closeTerrainPt.getX();
			this.y = (int)closeTerrainPt.getY();
			this.moveLeft -= Utils.inchDist(rootX, rootY, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY());
			this.contactTerrain(closeTerrain);
		}
		// Otherwise if we're hitting a unit check if we can contact it
		else if (closeUnit != null && Utils.inchDist(rootX, rootY, newX, newY) <= this.moveLeft) {
			System.out.println("Contacting unit: " + closeUnit.toChoiceString());
			System.out.println("NewX/Y: " + newX + " " + newY);
			System.out.println("Unit X/Y: " + closeUnit.x + " " + closeUnit.y);
			if (!this.canContact(closeUnit)) {
				return;
			}
			else if (closeUnit.isTerrifying()){
				System.out.println("Charging a TERRIFYING enemy");
				final int finalNewX = newX;
				final int finalNewY = newY;
				final Unit finalCloseUnit = closeUnit;
				Button doneTesting = new Button();
				doneTesting.addMouseListener(new MouseListener(){
					public void mouseClicked(MouseEvent arg0) {
						if (!passedChargeTest) {
							// Failed to charge a terrifying enemy, lose all move and can't use magic
							moveLeft = 0;
							hasUsedMagic = true;
						}
						else {
							// Passed the courage test
							uncontactTerrain();
							uncontactUnits();
							moveLeft -= Utils.inchDist(rootX, rootY, finalNewX, finalNewY);
							contact(finalCloseUnit);
							x = finalNewX;
							y = finalNewY;
						}
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent arg0) {}
					public void mousePressed(MouseEvent arg0) {}
					public void mouseReleased(MouseEvent arg0) {}
				});
				this.takeCourageTest(doneTesting, "Charge");
			}		
			else {
				this.uncontactTerrain();
				this.uncontactUnits();
				this.moveLeft -= Utils.inchDist(rootX, rootY, newX, newY);
				this.contact(closeUnit);
				this.x = newX;
				this.y = newY;
			}
		}
		// Otherwise just move normally
		else if (Utils.inchDist(rootX, rootY, newX, newY) <= this.moveLeft){
			this.uncontactTerrain();
			this.uncontactUnits();
			this.x = newX;
			this.y = newY;
			this.moveLeft -= Utils.inchDist(rootX, rootY, newX, newY);
		}
	}
	
	public void retreatMove(int destX, int destY) {
		if (this.moveLeft == 0)
			return;
		else if (this.isTransfixed) {
			UI.messageLog.add(this.toChoiceString() + " is transfixed/immobilized!");
			return;
		}
		if (destX < 0 || destX > game.board.pixelWidth 
				|| destY < 0 || destY > game.board.pixelHeight)
			return;
		int rootX = this.x;
		int rootY = this.y;
		int newX = destX;
		int newY = destY;
		double shortDist = Utils.inchDist(rootX, rootY, newX, newY);
		Unit closeUnit = null;
		
		for(Army a : game.armies){
			for(Unit u : a.units) {
				if (u.id != this.id){
					Point2D p = Utils.findContactPoint(this, u, destX, destY);
					
					if (p == null)
						continue;
					
					double x = Utils.inchDist(rootX, rootY, (int)p.getX(), (int)p.getY());
					if (x < shortDist) {
						newX = (int)p.getX();
						newY = (int)p.getY();
						shortDist = x;
						closeUnit = u;
					}
				}
			}
		}
		
		
		Point2D closeTerrainPt = null;
		Point2D candidate;
		Terrain closeTerrain = null;
		for (Terrain t : game.board.terrainList) {
			candidate = t.contactPoint(rootX, rootY, destX, destY, this.pixelRadius);
			if (candidate != null && (closeTerrainPt == null || 
					candidate.distance(rootX, rootY) < closeTerrainPt.distance(rootX, rootY))){
				closeTerrainPt = (Point2D)candidate.clone();
				closeTerrain = t;
			}
		}
		
		// If nearest terrain is a low wall with an enemy behind it, can't retreat there
		if (closeTerrain != null && closeTerrain instanceof LowWallRect &&
				((LowWallRect)closeTerrain).enemyAcrossBarrier(this, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY())) {
			return;
		}
		// If nearest terrain is closer than closest unit, move there
		else if (closeTerrainPt != null && closeTerrainPt.getX() != -1 &&
				Utils.inchDist(rootX, rootY, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY()) <= this.moveLeft
				&& (closeUnit == null || (closeUnit != null && closeTerrainPt.distance(rootX, rootY) < Utils.pixelDist(rootX, rootY, newX, newY)))){
			this.uncontactTerrain();
			this.uncontactUnits();
			this.x = (int)closeTerrainPt.getX();
			this.y = (int)closeTerrainPt.getY();
			this.moveLeft -= Utils.inchDist(rootX, rootY, (int)closeTerrainPt.getX(), (int)closeTerrainPt.getY());
			this.contactTerrain(closeTerrain);
		}
		else if (closeUnit != null) {
			// Can't retreat into contact with a unit
			return;
		}
		else if (Utils.inchDist(rootX, rootY, newX, newY) <= this.moveLeft){
			this.uncontactTerrain();
			this.uncontactUnits();
			this.x = newX;
			this.y = newY;
			this.moveLeft -= Utils.inchDist(rootX, rootY, newX, newY);
		}
	}
	
	public void uncontactTerrain() {
		for (Terrain t : this.terrainContacted) {
			t.uncontactedByUnit(this);
		}
		this.terrainContacted.clear();
	}
	
	public void contactTerrain(Terrain t) {
		this.terrainContacted.add(t);
		t.contactedByUnit(this);
	}
	
	public void uncontactUnits() {
		for (Unit u : this.unitsContacted) {
			u.unitsContacted.remove(this);
		}
		this.unitsContacted.clear();
		if (this.supporting != null) {
			this.supporting.supporters.remove(this);
			this.supporting = null;
		}
	}
	
	public boolean canContact(Unit u) {
		if (this.army == u.army) {
			return true;
		}
		else if (this.layingDown) {
			return false;
		}
		else if (u.battle == null) {
			return true;
		}
		else if (u.battle.majority == -1 || u.battle.majority == this.armyIndex)
			return true;
		return false;
	}
	
	public boolean canSee(Unit target) {
		// Check if any terrain blocking
		boolean partialBlocking = false;
		for(Terrain t : game.board.terrainList) {
			int losBlock = t.blocksLOS(this, target);
			if(losBlock == Terrain.FULLY_BLOCKED){
				return false;
			}
			else if(losBlock == Terrain.PARTIAL_BLOCKED &&
					!terrainContacted.contains(t)) {
				partialBlocking = true;
			}
		}
		
		// A partially obscured unit has a 50/50 chance of being spotted (unless wearing an Elven Cloak)
		// However, we also need to be consistent throughout a given turn and unit, so we set the seed
		// before randomizing
		if (partialBlocking) {
			if (target.hasEquipment(new ElvenCloak()) && Utils.inchDist(this, target) > 6)
				return false;
			else if (target.layingDown) {
				rng.setSeed(game.turnNumber + target.id*7919);
				boolean visible = rng.nextBoolean();
				rng = new Random();
				return visible;
			}
		}
		return true;
	}

	public Button getTerrainInteract() {
		if (this.terrainContacted.size() == 0)
			return null;
		else {
			Terrain t = this.terrainContacted.get(0);
			Button interact = t.getInteraction(this);
			return interact;
		}
	}
	

	public DieRoll jumpRoll() {
		DieRoll jumpRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, game.myUI);
		return jumpRoll;
		
	}
	
	public void contact(Unit u) {
		if (this == u)
			return;
		this.unitsContacted.add(u);
		u.unitsContacted.add(this);
		if (this.army != u.army) {
			u.moveLeft = 0;
			this.moveLeft = 0;
			if (u.battle == null) {
				if (u.supporting != null) {
					u.supporting.supporters.remove(u);
					u.supporting = null;
				}
				Battle b = new Battle(game);
				b.chargerIndex = this.armyIndex;
				b.addUnit(this);
				b.addUnit(u);
				game.battles.add(b);
				u.battle = b;
				this.battle = b;
			}
			else {
				u.battle.addUnit(this);
				this.battle = u.battle;
				if (u.battle instanceof BarrierBattle && ((BarrierBattle)u.battle).defenderIndex == u.armyIndex) {
					((BarrierBattle)u.battle).attackFromBothSides = true;
				}
			}
		}
		else {
			if (this.hasEquipment(new Spear()) && this.pixelRadius >= u.pixelRadius) {
				this.supporting = u;
				u.supporters.add(this);
			}
			if (u.hasEquipment(new Spear()) && u.pixelRadius >= this.pixelRadius) {
				u.supporting = this;
				this.supporters.add(u);
			}
		}
	}
	
	public void strike(Unit target, Button doneStriking) {
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		int neededToWound = Utils.neededToWound(this.getStrength(), target.getDefense());
		DieRoll strikeRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-130, 
										 this.woundBonus, neededToWound+"+ to wound", game.myUI);
		
		// Can't use might for strike
		if (!strikeRoll.isModifiable()) {
			strikeRoll.cleanup();
			UI.messageLog.add(this.toChoiceString() + " is attacking " 
					+ target.toChoiceString() + " with roll of " + strikeRoll.getRoll());
			target.takeStrike(this.getStrength(), strikeRoll.getRoll());
			if (game.myUI.getByName("fateButton") == null) {
				game.myUI.reenableComponents();
				game.myUI.disableMight();
				if (doneStriking != null) {
					System.out.println("DISPATCHING1");
					doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
												System.currentTimeMillis(), 0, 10, 10, 1, false));
				}
			}
			else {
				for (Component c : game.myUI.getComponents()) {
					if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
						((Button)c).addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								game.myUI.reenableComponents();
								game.myUI.disableMight();
								if (doneStriking != null){
									System.out.println("DISPATCHING2");
									doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
											System.currentTimeMillis(), 0, 10, 10, 1, false));
								}
							}
						});
					}
					else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
						((Button)c).addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								game.myUI.doneUsingMight.addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										game.myUI.reenableComponents();
										game.myUI.disableMight();
										if (doneStriking != null) {
											System.out.println("DISPATCHING3");
											doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
													System.currentTimeMillis(), 0, 10, 10, 1, false));
										}
									}
								});
							}
						});
					}
				}
			}
		}
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					strikeRoll.cleanup();
					UI.messageLog.add(toChoiceString() + " is attacking " 
							+ target.toChoiceString() + " with roll of " + strikeRoll.getRoll());
					target.takeStrike(strength, strikeRoll.getRoll());
					if (game.myUI.getByName("fateButton") == null) {
						game.myUI.reenableComponents();
						game.myUI.disableMight();
						if (doneStriking != null){
							System.out.println("DISPATCHING4");
							doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
									System.currentTimeMillis(), 0, 10, 10, 1, false));
						}
					}
					else {
						for (Component c : game.myUI.getComponents()) {
							if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
								((Button)c).addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										game.myUI.reenableComponents();
										game.myUI.disableMight();
										if (doneStriking != null) {
											System.out.println("DISPATCHING5");
											doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
													System.currentTimeMillis(), 0, 10, 10, 1, false));
										}
									}
								});
							}
							else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
								((Button)c).addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										game.myUI.doneUsingMight.addActionListener(new ActionListener() {
											public void actionPerformed(ActionEvent e) {
												game.myUI.reenableComponents();
												game.myUI.disableMight();
												if (doneStriking != null){
													System.out.println("DISPATCHING6");
													doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
															System.currentTimeMillis(), 0, 10, 10, 1, false));
												}
											}
										});
									}
								});
							}
						}
					}
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	public void strike(Unit target, boolean hasRetreated, Button doneStriking) {
		if (hasRetreated){
			this.strike(target, doneStriking);
			return;
		}
		// Otherwise, we're trapped
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		int neededToWound = Utils.neededToWound(this.getStrength(), target.getDefense());
		DieRoll strikeRoll1 = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-130, 
										 this.woundBonus, neededToWound+"+ to wound", game.myUI);
		DieRoll strikeRoll2 = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-160, 
				 						 this.woundBonus, neededToWound+"+ to wound", game.myUI);

		
		// Can't use might for strike
		if (!strikeRoll1.isModifiable() && !strikeRoll2.isModifiable()) {
			UI.messageLog.add(this.toChoiceString() + " is attacking trapped " 
					+ target.toChoiceString() + " with rolls of " + strikeRoll1.getRoll() + " " + strikeRoll2.getRoll());
			target.takeStrike(this.getStrength(), strikeRoll1.getRoll());
			if (game.myUI.getByName("fateButton") == null) {
				target.takeStrike(strength, strikeRoll2.getRoll());
				if (game.myUI.getByName("fateButton") == null) {
					strikeRoll1.cleanup();
					strikeRoll2.cleanup();
					game.myUI.reenableComponents();
					if (doneStriking != null)
						doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
								System.currentTimeMillis(), 0, 10, 10, 1, false));
				}
				else {
					for (Component c : game.myUI.getComponents()) {
						if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
							((Button)c).addActionListener(new ActionListener() {
								public void actionPerformed(ActionEvent e) {
									strikeRoll1.cleanup();
									strikeRoll2.cleanup();
									game.myUI.reenableComponents();
									if (doneStriking != null)
										doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
												System.currentTimeMillis(), 0, 10, 10, 1, false));
								}
							});
						}
						else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
							((Button)c).addActionListener(new ActionListener() {
								public void actionPerformed(ActionEvent e) {
									game.myUI.doneUsingMight.addActionListener(new ActionListener() {
										public void actionPerformed(ActionEvent e) {
											strikeRoll1.cleanup();
											strikeRoll2.cleanup();
											game.myUI.reenableComponents();
											if (doneStriking != null)
												doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
														System.currentTimeMillis(), 0, 10, 10, 1, false));
										}
									});
								}
							});
						}
					}
				}
			}
			else {
				for (Component c : game.myUI.getComponents()) {
					if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
						((Button)c).addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								target.takeStrike(strength, strikeRoll2.getRoll());
								if (game.myUI.getByName("fateButton") == null) {
									strikeRoll1.cleanup();
									strikeRoll2.cleanup();
									game.myUI.reenableComponents();
									if (doneStriking != null)
										doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
												System.currentTimeMillis(), 0, 10, 10, 1, false));
								}
								else {
									for (Component c : game.myUI.getComponents()) {
										if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
											((Button)c).addActionListener(new ActionListener() {
												public void actionPerformed(ActionEvent e) {
													strikeRoll1.cleanup();
													strikeRoll2.cleanup();
													game.myUI.reenableComponents();
													if (doneStriking != null)
														doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
																System.currentTimeMillis(), 0, 10, 10, 1, false));
												}
											});
										}
										else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
											((Button)c).addActionListener(new ActionListener() {
												public void actionPerformed(ActionEvent e) {
													game.myUI.doneUsingMight.addActionListener(new ActionListener() {
														public void actionPerformed(ActionEvent e) {
															strikeRoll1.cleanup();
															strikeRoll2.cleanup();
															game.myUI.reenableComponents();
															if (doneStriking != null)
																doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
																		System.currentTimeMillis(), 0, 10, 10, 1, false));
														}
													});
												}
											});
										}
									}
								}
								game.myUI.reenableComponents();
							}
						});
					}
					else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
						((Button)c).addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								game.myUI.doneUsingMight.addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										target.takeStrike(strength, strikeRoll2.getRoll());
										if (game.myUI.getByName("fateButton") == null) {
											strikeRoll1.cleanup();
											strikeRoll2.cleanup();
											game.myUI.reenableComponents();
											if (doneStriking != null)
												doneStriking.dispatchEvent(null);
										}
										else {
											for (Component c : game.myUI.getComponents()) {
												if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
													((Button)c).addActionListener(new ActionListener() {
														public void actionPerformed(ActionEvent e) {
															strikeRoll1.cleanup();
															strikeRoll2.cleanup();
															game.myUI.reenableComponents();
															if (doneStriking != null)
																doneStriking.dispatchEvent(null);
														}
													});
												}
												else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
													((Button)c).addActionListener(new ActionListener() {
														public void actionPerformed(ActionEvent e) {
															game.myUI.doneUsingMight.addActionListener(new ActionListener() {
																public void actionPerformed(ActionEvent e) {
																	strikeRoll1.cleanup();
																	strikeRoll2.cleanup();
																	game.myUI.reenableComponents();
																	if (doneStriking != null)
																		doneStriking.dispatchEvent(null);
																}
															});
														}
													});
												}
											}
										}
										game.myUI.reenableComponents();
									}
								});
							}
						});
					}
				}
			}
			/*game.myUI.reenableComponents();
			if (doneStriking != null)
				doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));*/
		}
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " is attacking trapped " 
							+ target.toChoiceString() + " with rolls of " + strikeRoll1.getRoll()+ " " + strikeRoll2.getRoll());
					target.takeStrike(strength, strikeRoll1.getRoll());
					if (game.myUI.getByName("fateButton") == null) {
						target.takeStrike(strength, strikeRoll2.getRoll());
						if (game.myUI.getByName("fateButton") == null) {
							strikeRoll1.cleanup();
							strikeRoll2.cleanup();
							game.myUI.reenableComponents();
							game.myUI.disableMight();
							if (doneStriking != null)
								doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
										System.currentTimeMillis(), 0, 10, 10, 1, false));
						}
						else {
							for (Component c : game.myUI.getComponents()) {
								if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
									((Button)c).addActionListener(new ActionListener() {
										public void actionPerformed(ActionEvent e) {
											strikeRoll1.cleanup();
											strikeRoll2.cleanup();
											game.myUI.reenableComponents();
											game.myUI.disableMight();
											if (doneStriking != null)
												doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
														System.currentTimeMillis(), 0, 10, 10, 1, false));
										}
									});
								}
								else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
									((Button)c).addActionListener(new ActionListener() {
										public void actionPerformed(ActionEvent e) {
											game.myUI.doneUsingMight.addActionListener(new ActionListener() {
												public void actionPerformed(ActionEvent e) {
													strikeRoll1.cleanup();
													strikeRoll2.cleanup();
													game.myUI.reenableComponents();
													game.myUI.disableMight();
													if (doneStriking != null)
														doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
																System.currentTimeMillis(), 0, 10, 10, 1, false));
												}
											});
										}
									});
								}
							}
						}
					}
					else {
						for (Component c : game.myUI.getComponents()) {
							if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
								((Button)c).addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										target.takeStrike(strength, strikeRoll2.getRoll());
										if (game.myUI.getByName("fateButton") == null) {
											strikeRoll1.cleanup();
											strikeRoll2.cleanup();
											game.myUI.reenableComponents();
											game.myUI.disableMight();
											if (doneStriking != null)
												doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
														System.currentTimeMillis(), 0, 10, 10, 1, false));
										}
										else {
											for (Component c : game.myUI.getComponents()) {
												if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
													((Button)c).addActionListener(new ActionListener() {
														public void actionPerformed(ActionEvent e) {
															strikeRoll1.cleanup();
															strikeRoll2.cleanup();
															game.myUI.reenableComponents();
															game.myUI.disableMight();
															if (doneStriking != null)
																doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
																		System.currentTimeMillis(), 0, 10, 10, 1, false));
														}
													});
												}
												else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
													((Button)c).addActionListener(new ActionListener() {
														public void actionPerformed(ActionEvent e) {
															game.myUI.doneUsingMight.addActionListener(new ActionListener() {
																public void actionPerformed(ActionEvent e) {
																	strikeRoll1.cleanup();
																	strikeRoll2.cleanup();
																	game.myUI.reenableComponents();
																	game.myUI.disableMight();
																	if (doneStriking != null)
																		doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
																				System.currentTimeMillis(), 0, 10, 10, 1, false));
																}
															});
														}
													});
												}
											}
										}
										/*
										game.myUI.reenableComponents();
										game.myUI.disableMight();*/
									}
								});
							}
							else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
								((Button)c).addActionListener(new ActionListener() {
									public void actionPerformed(ActionEvent e) {
										game.myUI.doneUsingMight.addActionListener(new ActionListener() {
											public void actionPerformed(ActionEvent e) {
												target.takeStrike(strength, strikeRoll2.getRoll());
												if (game.myUI.getByName("fateButton") == null) {
													strikeRoll1.cleanup();
													strikeRoll2.cleanup();
													game.myUI.reenableComponents();
													game.myUI.disableMight();
													if (doneStriking != null)
														doneStriking.dispatchEvent(null);
												}
												else {
													for (Component c : game.myUI.getComponents()) {
														if (c instanceof Button && ((Button)c).getLabel().equals("Don't use fate")) {
															((Button)c).addActionListener(new ActionListener() {
																public void actionPerformed(ActionEvent e) {
																	strikeRoll1.cleanup();
																	strikeRoll2.cleanup();
																	game.myUI.reenableComponents();
																	game.myUI.disableMight();
																	if (doneStriking != null)
																		doneStriking.dispatchEvent(null);
																}
															});
														}
														else if (c instanceof Button && ((Button)c).getLabel().equals("Use fate")) {
															((Button)c).addActionListener(new ActionListener() {
																public void actionPerformed(ActionEvent e) {
																	game.myUI.doneUsingMight.addActionListener(new ActionListener() {
																		public void actionPerformed(ActionEvent e) {
																			strikeRoll1.cleanup();
																			strikeRoll2.cleanup();
																			game.myUI.reenableComponents();
																			game.myUI.disableMight();
																			if (doneStriking != null)
																				doneStriking.dispatchEvent(null);
																		}
																	});
																}
															});
														}
													}
												}
												/*game.myUI.reenableComponents();
												game.myUI.disableMight();*/
											}
										});
									}
								});
							}
						}
					}
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	public void takeStrike(int strength, int roll) {
		if (!Utils.wound(roll, strength, this.getDefense())) {
			return;
		}
		if (this.checkFuryEffect()) {
			int furyRoll = rng.nextInt(6) + 1;
			UI.messageLog.add("Rolling for Fury save (6+): " + furyRoll);
			if (furyRoll >= 6)
				return;
		}
		else if (this.getFate() <= 0) {
			this.takeWound(1);
			if (this.getWounds() <= 0)
				this.die();
			game.myUI.repaint();
		}
		else {
			Button useFate = new Button("Use fate");
			useFate.setName("fateButton");
			useFate.setBounds(game.myUI.dim.width-100, 0, 100, 100);
			
			Button noFate = new Button("Don't use fate");
			noFate.setName("fateButton");
			noFate.setBounds(game.myUI.dim.width-100, 100, 100, 100);
			
			final Unit thisUnit = this;
			
			useFate.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					DieRoll fateRoll = new DieRoll(thisUnit, game.myUI.dim.width-200, game.myUI.dim.height/2-130, "4+ to save", game.myUI);
					useFate(1);
					if (!fateRoll.isModifiable()) {
						int fateNum = fateRoll.getRoll();
						UI.messageLog.add(toChoiceString() + " rolling for fate: " + fateNum);
						game.myUI.removeByName("fateButton");
						game.myUI.reenableComponents();
						fateRoll.cleanup();
						if (fateNum < 4) {
							takeStrike(strength, roll);
						}
						game.myUI.repaint();
					}
					else {
						useFate.setEnabled(false);
						noFate.setEnabled(false);
						ActionListener mightDone = new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								int fateNum = fateRoll.getRoll();
								UI.messageLog.add(toChoiceString() + " rolling for fate: " + fateNum);
								game.myUI.removeByName("fateButton");
								game.myUI.reenableComponents();
								fateRoll.cleanup();
								game.myUI.disableMight();
								if (fateNum < 4) {
									takeStrike(strength, roll);
								}
								game.myUI.repaint();
							}
						};
						game.myUI.enableMight(mightDone);
					}
				}
			});
			
			noFate.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					game.myUI.removeByName("fateButton");
					game.myUI.reenableComponents();
					takeWound(1);
					if (getWounds() <= 0)
						die();
					game.myUI.repaint();
				}
			});
			
			game.myUI.storeVisibleComponents();
			game.myUI.disableComponents();
						
			game.myUI.add(useFate);
			game.myUI.add(noFate);
		}
	}
	
	public void takeStrike(int strength, int roll, Button doneStriking) {
		if (!Utils.wound(roll, strength, this.getDefense())) {
			if (doneStriking != null)
				doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));
			game.myUI.repaint();
			return;
		}
		if (this.checkFuryEffect()) {
			int furyRoll = rng.nextInt(6) + 1;
			UI.messageLog.add("Rolling for Fury save (6+): " + furyRoll);
			if (furyRoll >= 6) {
				if (doneStriking != null)
					doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
							System.currentTimeMillis(), 0, 10, 10, 1, false));
				game.myUI.repaint();
				return;
			}
		}
		else if (this.getFate() <= 0) {
			this.takeWound(1);
			if (this.getWounds() <= 0)
				this.die();
			if (doneStriking != null)
				doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));
			game.myUI.repaint();
		}
		else {
			game.myUI.storeVisibleComponents();
			game.myUI.disableComponents();
			
			Button useFate = new Button("Use fate");
			useFate.setName("fateButton");
			useFate.setBounds(game.myUI.dim.width-100, 0, 100, 100);
			
			Button noFate = new Button("Don't use fate");
			noFate.setName("fateButton");
			noFate.setBounds(game.myUI.dim.width-100, 100, 100, 100);
			
			final Unit thisUnit = this;
			
			useFate.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					DieRoll fateRoll = new DieRoll(thisUnit, game.myUI.dim.width-200, game.myUI.dim.height/2-130, "4+ to save", game.myUI);
					useFate(1);
					if (!fateRoll.isModifiable()) {
						int fateNum = fateRoll.getRoll();
						UI.messageLog.add(toChoiceString() + " rolling for fate: " + fateNum);
						game.myUI.removeByName("fateButton");
						fateRoll.cleanup();
						if (fateNum < 4) {
							takeStrike(strength, roll, doneStriking);
						}
						else {
							game.myUI.reenableComponents();
							if (doneStriking != null)
								doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
										System.currentTimeMillis(), 0, 10, 10, 1, false));
						}
						game.myUI.repaint();
					}
					else {
						useFate.setEnabled(false);
						noFate.setEnabled(false);
						ActionListener mightDone = new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								int fateNum = fateRoll.getRoll();
								UI.messageLog.add(toChoiceString() + " rolling for fate: " + fateNum);
								game.myUI.removeByName("fateButton");
								fateRoll.cleanup();
								game.myUI.disableMight();
								if (fateNum < 4) {
									takeStrike(strength, roll, doneStriking);
								}
								else {
									game.myUI.reenableComponents();
									if (doneStriking != null)
										doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
												System.currentTimeMillis(), 0, 10, 10, 1, false));
								}
								game.myUI.repaint();
							}
						};
						game.myUI.enableMight(mightDone);
					}
				}
			});
			
			noFate.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					game.myUI.removeByName("fateButton");
					game.myUI.reenableComponents();
					takeWound(1);
					if (getWounds() <= 0)
						die();
					if (doneStriking != null)
						doneStriking.dispatchEvent(new MouseEvent(doneStriking, MouseEvent.MOUSE_CLICKED, 
								System.currentTimeMillis(), 0, 10, 10, 1, false));
					game.myUI.repaint();
				}
			});
			
						
			game.myUI.add(useFate);
			game.myUI.add(noFate);
		}
	}
	
	public void resistMagic(int rollToBeat, Button resistSucceed, Button resistFail) {
		if (this.getWill() <= 0) {
			resistFail.dispatchEvent(new MouseEvent(resistFail, MouseEvent.MOUSE_CLICKED, 
					System.currentTimeMillis(), 0, 10, 10, 1, false));
			return;
		}
		
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		Button useWill = new Button("Resist with Will");
		useWill.setName("resistButton");
		useWill.setBounds(game.myUI.dim.width-100, 0, 100, 100);
		
		Button noWill = new Button("Don't resist");
		noWill.setName("resistButton");
		noWill.setBounds(game.myUI.dim.width-100, 100, 100, 100);
		
		final Unit thisUnit = this;
		
		useWill.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				final NumberSelecter diceToResist = new NumberSelecter(1,willLeft,1,"Use how much will?", game.myUI, null);;
				
				Button codeToExecute = new Button();
				codeToExecute.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent arg0) {
						ArrayList<DieRoll> willRolls = new ArrayList<DieRoll>();
						boolean isModifiable = false;
						for (int i = 0; i < diceToResist.getNumber(); i++) {
							DieRoll willRoll = new DieRoll(thisUnit, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), rollToBeat+"+ to resist", game.myUI);
							willRolls.add(willRoll);
							if (willRoll.isModifiable())
								isModifiable = true;
						}
						useWill(diceToResist.getNumber());
						if (!isModifiable) {
							UI.messageLog.add(toChoiceString() + " rolling to resist: " + willRolls);
							int willNum = 0;
							for (DieRoll dr : willRolls) {
								willNum = Math.max(willNum, dr.getRoll());
								dr.cleanup();
							}
							game.myUI.removeByName("resistButton");
							if (willNum < rollToBeat) {
								game.myUI.reenableComponents();
								if (resistFail != null)
									resistFail.dispatchEvent(new MouseEvent(resistFail, MouseEvent.MOUSE_CLICKED, 
											System.currentTimeMillis(), 0, 10, 10, 1, false));
							}
							else {
								game.myUI.reenableComponents();
								if (resistSucceed != null)
									resistSucceed.dispatchEvent(new MouseEvent(resistSucceed, MouseEvent.MOUSE_CLICKED, 
											System.currentTimeMillis(), 0, 10, 10, 1, false));
							}
							game.myUI.repaint();
						}
						else {
							System.out.println("Is modifiable");
							System.out.println(game.myUI.endPhase.isVisible());
							useWill.setEnabled(false);
							noWill.setEnabled(false);
							
							ActionListener mightDone = new ActionListener() {
								public void actionPerformed(ActionEvent e) {
									int willNum = 0;
									for (DieRoll dr : willRolls) {
										willNum = Math.max(willNum, dr.getRoll());
										dr.cleanup();
									}
									UI.messageLog.add(toChoiceString() + " rolling to resist: " + willRolls);
									game.myUI.removeByName("resistButton");
									game.myUI.disableMight();
									if (willNum < rollToBeat) {
										game.myUI.reenableComponents();
										if (resistFail != null)
											resistFail.dispatchEvent(new MouseEvent(resistFail, MouseEvent.MOUSE_CLICKED, 
													System.currentTimeMillis(), 0, 10, 10, 1, false));
									}
									else {
										game.myUI.reenableComponents();
										if (resistSucceed != null)
											resistSucceed.dispatchEvent(new MouseEvent(resistSucceed, MouseEvent.MOUSE_CLICKED, 
													System.currentTimeMillis(), 0, 10, 10, 1, false));
									}
									game.myUI.repaint();
								}
							};
							game.myUI.enableMight(mightDone);
						}
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent arg0) {}
					public void mousePressed(MouseEvent arg0) {}
					public void mouseReleased(MouseEvent arg0) {}
				});
				diceToResist.setCodeToExecute(codeToExecute);
			}
		});
		
		noWill.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				game.myUI.removeByName("resistButton");
				game.myUI.reenableComponents();
				if (resistFail != null)
					resistFail.dispatchEvent(new MouseEvent(resistFail, MouseEvent.MOUSE_CLICKED, 
							System.currentTimeMillis(), 0, 10, 10, 1, false));
				game.myUI.repaint();
			}
		});
		
		game.myUI.add(useWill);
		game.myUI.add(noWill);
	}
		
	public void shootAt(Unit target) {
		// Ensure we're allowed to shoot
		if (Utils.inchDist(this, target) > this.shootRange 
				|| this.moveLeft < this.move * this.moveNeededToShoot
				|| this.battle != null
				|| (target.battle != null && this.armyIndex == Game.GOODINDEX)
				|| this.hasShot) {
			if (Utils.inchDist(this, target) > this.shootRange)
				UI.messageLog.add("Too far away!");
			else if (this.moveLeft < this.move * this.moveNeededToShoot)
				UI.messageLog.add("Already moved too far this turn, can't shoot");
			else if (this.battle != null)
				UI.messageLog.add("In a fight, can't shoot");
			else if (target.battle != null && this.armyIndex == Game.GOODINDEX)
				UI.messageLog.add("Good units can't shoot into fights");
			else if (this.hasShot)
				UI.messageLog.add("Already shot");
			else if (this.layingDown)
				UI.messageLog.add("Can't shoot while laying down");
			else if (!this.canSee(target))
				UI.messageLog.add("Can't see the target!");
			((ShootUI)game.myUI.phaseUI).setShooting(false);
			game.myUI.repaint();
			return;
		}
		
		// Check for vision/get number of obstacles
		ArrayList<Terrain> losBlockers = new ArrayList<Terrain>();
		ArrayList<Unit> losUnits = new ArrayList<Unit>();
		for(Terrain t : game.board.terrainList) {
			int losBlock = t.blocksLOS(this, target);
			if(losBlock == Terrain.FULLY_BLOCKED){
				UI.messageLog.add("Blocked by an obstacle");
				((ShootUI)game.myUI.phaseUI).setShooting(false);
				game.myUI.repaint();
				return;
			}
			else if(losBlock == Terrain.PARTIAL_BLOCKED &&
					!terrainContacted.contains(t)) {
				losBlockers.add(t);
			}
		}
		class CustomComp implements Comparator<Terrain>{
			public Unit shooter;
			public Unit target;
			public CustomComp(Unit shooter, Unit target) {
				this.shooter = shooter;
				this.target = target;
			}
			public int compare(Terrain t1, Terrain t2) {
				Point2D t1Point = t1.contactPoint(shooter.x, shooter.y, target.x, target.y, shooter.pixelRadius);
				Point2D t2Point = t2.contactPoint(shooter.x, shooter.y, target.x, target.y, shooter.pixelRadius);
				return (int)Math.round(Utils.pixelDist(t1Point.getX(), t1Point.getY(), shooter.x, shooter.y) -
						Utils.pixelDist(t2Point.getX(), t2Point.getY(), shooter.x, shooter.y));
			}
		}
		CustomComp myTComp = new CustomComp(this,target);
		Collections.sort(losBlockers, myTComp);
		
		for(Army a : game.armies){
			for(Unit unit : a.units){
				if (unit != this && unit != target && unit.blocksLOS(this, target)
						&& !this.unitsContacted.contains(unit)) {
					losUnits.add(unit);
				}
			}
		}
		class CustomCompU implements Comparator<Unit>{
			public Unit shooter;
			public CustomCompU(Unit shooter) {
				this.shooter = shooter;
			}
			public int compare(Unit u1, Unit u2) {
				return (int)Math.round(Utils.pixelDist(u1.x, u1.y, shooter.x, shooter.y) -
						Utils.pixelDist(u2.x, u2.y, shooter.x, shooter.y));
			}
		}
		CustomCompU myUComp = new CustomCompU(this);
		Collections.sort(losUnits, myUComp);
		// If you're a good guy, you can't shoot past own units.
		if(this.armyIndex == Game.GOODINDEX){
			for(Unit unit : losUnits) {
				if (unit.armyIndex == this.armyIndex) {
					UI.messageLog.add("Good units can't shoot with own units partially blocking");
					((ShootUI)game.myUI.phaseUI).setShooting(false);
					game.myUI.repaint();
					return;
				}
			}
		}
		
		if (losUnits.size() == 0)
			UI.messageLog.add(this.toChoiceString() + " is shooting at " + target.toChoiceString() + " with " + 
							losBlockers.size() + " obstacles");
		else 
			UI.messageLog.add(this.toChoiceString() + " is shooting at " + target.toChoiceString() + " with " + 
					losBlockers.size() + " obstacles and " + losUnits.size() + " units in the way");
		this.hasShot = true;
		
		this.shootForHit(target, losBlockers, losUnits);
		
		
		
		
		
	}
	
	public void shootForHit(Unit target, ArrayList<Terrain> losBlockers, ArrayList<Unit> losUnits) {
		int requiredToHit = this.shootValue;
		if (target.checkBlindingLight())
			requiredToHit = 6;
		final int requiredToHitFinal = requiredToHit;
		// Roll to hit
		DieRoll hitRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, requiredToHit+"+ to Hit", game.myUI);
		
		// No way to use might
		if (!hitRoll.isModifiable()) {
			int hitNum = hitRoll.getRoll();
			UI.messageLog.add("Roll to hit: " + hitNum);
			hitRoll.cleanup();
			if (hitNum < requiredToHit){
				((ShootUI)game.myUI.phaseUI).setShooting(false);
				game.myUI.repaint();
				return; // Missed
			}
			else {
				shootForObstacles(target, losBlockers, losUnits);
			}
		}
		// Otherwise, allow for it
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					int hitNum = hitRoll.getRoll();
					UI.messageLog.add("Roll to hit: " + hitNum);
					if (hitNum < requiredToHitFinal){
						hitRoll.cleanup();
						game.myUI.disableMight();
						((ShootUI)game.myUI.phaseUI).setShooting(false);
						game.myUI.repaint();
						return; // Missed
					}
					else {
						hitRoll.cleanup();
						game.myUI.disableMight();
						game.myUI.repaint();
						shootForObstacles(target, losBlockers, losUnits);
					}
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	public void shootForObstacles(Unit target, ArrayList<Terrain> losBlockers, ArrayList<Unit> losUnits) {
		if (losBlockers.size() == 0 && losUnits.size() == 0) {
			// Nothing left in the way, roll to wound
			shootForWound(target);
			return;
		}
		
		// Roll for obstacles and units
		boolean obsClosest = true;
		// Check whether an obstacle or unit is next
		if (losBlockers.size() == 0)
			obsClosest = false;
		else if (losUnits.size() == 0)
			obsClosest = true;
		else {
			Point2D obsPoint = losBlockers.get(0).contactPoint(this.x, this.y, target.x, target.y, this.pixelRadius);
			Unit closeUnit = losUnits.get(0);
			if (Utils.pixelDist(obsPoint.getX(), obsPoint.getY(), this.x, this.y) < 
					Utils.pixelDist(closeUnit.x, closeUnit.y, this.x, this.y))
				obsClosest = true;
			else
				obsClosest = false;
		}
		// If an obstacle is closest, check if we hit that.
		if (obsClosest) {
			Terrain obstacle = losBlockers.get(0);
			losBlockers.remove(0);
			DieRoll obsRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, "4+ to avoid", game.myUI);
			
			if (!obsRoll.isModifiable()) {
				int obsNum = obsRoll.getRoll();
				obsRoll.cleanup();
				UI.messageLog.add("Roll for obstacle " + obstacle.toMessageString() + ": " + 
									obsNum);
				if(obsNum < 4){
					((ShootUI)game.myUI.phaseUI).setShooting(false);
					game.myUI.repaint();
					return;  // Hit the obstacle
				}
				else {
					// Made it past, recurse on smaller list
					obsRoll.cleanup();
					shootForObstacles(target, losBlockers, losUnits);
				}
			}
			else {
				ActionListener mightDone = new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						int obsNum = obsRoll.getRoll();
						obsRoll.cleanup();
						UI.messageLog.add("Roll for obstacle: " + obsNum);
						if (obsNum < 4){
							obsRoll.cleanup();
							game.myUI.disableMight();
							((ShootUI)game.myUI.phaseUI).setShooting(false);
							game.myUI.repaint();
							return; // Missed
						}
						else {
							// Passed the obstacle, recurse on smaller lists
							obsRoll.cleanup();
							game.myUI.disableMight();
							game.myUI.repaint();
							shootForObstacles(target, losBlockers, losUnits);
						}
					}
				};
				game.myUI.enableMight(mightDone);
			}
		}
		// Otherwise, the next thing to roll for is a unit
		else {
			DieRoll obsRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, "4+ to avoid", game.myUI);
			Unit unitObstacle = losUnits.get(0);
			losUnits.remove(0);
			
			if (!obsRoll.isModifiable()) {
				int obsNum = obsRoll.getRoll();
				obsRoll.cleanup();
				UI.messageLog.add("Roll for unit " + unitObstacle.toChoiceString() + ": " + 
									obsNum);
				if(obsNum < 4){
					// Hit the unit, adjust target and move to wounding
					UI.messageLog.add("Final target is " + unitObstacle.toChoiceString());
					obsRoll.cleanup();
					shootForWound(unitObstacle);
				}
				else {
					// Made it past, recurse on smaller list
					obsRoll.cleanup();
					shootForObstacles(target, losBlockers, losUnits);
				}
			}
			else {
				ActionListener mightDone = new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						int obsNum = obsRoll.getRoll();
						obsRoll.cleanup();
						UI.messageLog.add("Roll for unit: " + obsNum);
						if (obsNum < 4){
							// Hit the unit, adjust target and move to wounding
							UI.messageLog.add("Final target is " + unitObstacle.toChoiceString());
							obsRoll.cleanup();
							game.myUI.disableMight();
							game.myUI.repaint();
							shootForWound(unitObstacle);
						}
						else {
							// Passed the obstacle, recurse on smaller lists
							obsRoll.cleanup();
							game.myUI.disableMight();
							game.myUI.repaint();
							shootForObstacles(target, losBlockers, losUnits);
						}
					}
				};
				game.myUI.enableMight(mightDone);
			}
		}
	}
	
	public void shootForWound(Unit target) {
		// If firing into a battle, check which side we hit.
		if (target.battle != null) {
			int sideRoll = rng.nextInt(2);
			UI.messageLog.add("Hit a battle, side hit is: " + sideRoll);
			if (sideRoll == 1) {
				double closestDist = 100;
				for (Unit t : target.battle.badUnits){
					if (Utils.inchDist(this, t) < closestDist) {
						closestDist = Utils.inchDist(this, t);
						target = t;
					}
				}
			}
			UI.messageLog.add("Final target is " + target.toChoiceString());
		}
		
		final Unit unitHit = target;
		
		DieRoll woundRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, 
										Utils.neededToWound(shootStrength, unitHit.getDefense())+"+ to wound", game.myUI);
		
		// No way to use might
		if (!woundRoll.isModifiable()) {
			int woundNum = woundRoll.getRoll();
			UI.messageLog.add("Roll to wound: " + woundNum);
			
			unitHit.takeStrike(this.shootStrength, woundNum);
			if (unitHit.getWounds() <= 0) {
				unitHit.die();
				game.myUI.targetedUnit = null;
			}
			woundRoll.cleanup();
			((ShootUI)game.myUI.phaseUI).setShooting(false);
			game.myUI.refreshSelectChoice();
			game.myUI.repaint();
		}
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					int woundNum = woundRoll.getRoll();
					UI.messageLog.add("Roll to wound: " + woundNum);
					unitHit.takeStrike(shootStrength, woundNum);
					if (unitHit.getWounds() <= 0 ) {
						unitHit.die();
						game.myUI.targetedUnit = null;
					}
					game.myUI.refreshSelectChoice();
					woundRoll.cleanup();
					game.myUI.disableMight();
					((ShootUI)game.myUI.phaseUI).setShooting(false);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	public Area getControlZone() {
		// If we're in a fight or laying down or transfixed, only control zone is our base
		if (this.battle != null || this.layingDown || this.isTransfixed) {
			Ellipse2D controlShape = new Ellipse2D.Double(x-this.pixelRadius, y-this.pixelRadius, 
					2*this.pixelRadius, 2*this.pixelRadius);
			return new Area(controlShape);
		}
		else {
			Ellipse2D controlShape = new Ellipse2D.Double(x-this.pixelRadius-Utils.pixelsPerInch, 
					y-this.pixelRadius-Utils.pixelsPerInch, 
					2*this.pixelRadius+2*Utils.pixelsPerInch, 
					2*this.pixelRadius+2*Utils.pixelsPerInch);
			return new Area(controlShape);
		}
	}
	
	public void takeCourageTest(Button doneTesting, String type) {
		if (this.checkCouragePass()){
			if (type.equals("Broken"))
				this.passedBrokenTest = true;
			else if (type.equals("Charge"))
				this.passedChargeTest = true;
			if (doneTesting != null)
				doneTesting.dispatchEvent(new MouseEvent(doneTesting, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));
			game.myUI.repaint();
			return;
		}
		
		if (type.equals("Broken") && this.checkStandFast()) {
			this.passedBrokenTest = true;
			if (doneTesting != null)
				doneTesting.dispatchEvent(new MouseEvent(doneTesting, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));
			game.myUI.repaint();
			return;
		}
		
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		if (type.equals("Charge"))
			this.passedChargeTest = false;
		else if (type.equals("Broken"))
			this.passedBrokenTest = false;
		
		int neededToPass = 10 - this.getCourage();
		CourageRoll courageRoll = new CourageRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-130, 
				 							neededToPass+"+ total to pass", game.myUI);
		
		// If we have no might or will, just check, update, and reenable buttons
		if (!courageRoll.isModifiable()) {
			int courageNum = courageRoll.getRoll();
			UI.messageLog.add(this.toChoiceString() + " rolls a " + courageNum + " for their courage test");
			courageRoll.cleanup();
			if (courageNum + courage >= 10) {
				if (type.equals("Charge"))
					this.passedChargeTest = true;
				else if (type.equals("Broken"))
					this.passedBrokenTest = true;
			}
			game.myUI.reenableComponents();
			if (doneTesting != null)
				doneTesting.dispatchEvent(new MouseEvent(doneTesting, MouseEvent.MOUSE_CLICKED, 
						System.currentTimeMillis(), 0, 10, 10, 1, false));
			game.myUI.repaint();
		}
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e){
					int courageNum = courageRoll.getRoll();
					UI.messageLog.add(toChoiceString() + " rolls a " + courageNum + " for their courage test");
					courageRoll.cleanup();
					if (courageNum + courage >= 10) {
						if (type.equals("Charge"))
							passedChargeTest = true;
						else if (type.equals("Broken"))
							passedBrokenTest = true;
					}
					game.myUI.disableMight();
					game.myUI.reenableComponents();
					if (doneTesting != null)
						doneTesting.dispatchEvent(new MouseEvent(doneTesting, MouseEvent.MOUSE_CLICKED, 
								System.currentTimeMillis(), 0, 10, 10, 1, false));
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	public boolean isTerrifying() {
		return (this.tempTerrifying);
	}
	
	public boolean checkStandFast() {
		for (Unit u : this.army.units){ 
			if (u instanceof Hero && ((Hero)u).givesStandFast(this))
				return true;
		}
		return false;
	}
	
	public boolean checkCouragePass() {
		for (Unit u : this.army.units){ 
			if (u instanceof Hero && ((Hero)u).givesCouragePass(this))
				return true;
		}
		return false;
	}
	
	public boolean checkFuryEffect() {
		for (Unit u : this.army.units){ 
			if (u instanceof Hero && ((Hero)u).hasFury && Utils.inchDist(this, u) <= 6)
				return true;
		}
		return false;
	}
	
	public boolean checkBlindingLight() {
		for (Unit u : this.army.units){ 
			if (u instanceof Hero && ((Hero)u).hasBlindingLight && Utils.inchDist(this, u) <= 6)
				return true;
		}
		return false;
	}
	
	public ArrayList<Button> getSpellButtons() {
		return new ArrayList<Button>();
	}
	
	public void layDown() {
		if (this.moveLeft < this.move / 2) {
			UI.messageLog.add("Not enough move left for " + toChoiceString() + " to lay down");
			game.myUI.repaint();
		}
		else {
			this.moveLeft -= this.move / 2;
			this.moveLeft = this.moveLeft / this.move;
			this.layingDown = true;
		}
	}
	public void standUp() {
		if (this.moveLeft < 0.5) {
			UI.messageLog.add("Not enough move left for " + toChoiceString() + " to stand up");
			game.myUI.repaint();
		}
		else {
			this.moveLeft -= 0.5;
			this.moveLeft = this.moveLeft * this.move;
			this.layingDown = false;
		}
	}
	
	public void knockDown() {
		if (this.layingDown)
			return;
		this.moveLeft = this.moveLeft / this.move;
		this.layingDown = true;
	}
	
	public void throwRider(Button doneThrowing) {
		if (!this.isCavalry())
			return;
		
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		// HARD-CODED ASSUMPTION: Riders are small-base units
		this.inchRadius = 0.5;
		this.pixelRadius = 15;
		for (Equipment e : this.equipmentList) {
			if (e instanceof Mount)
				this.equipmentList.remove(e);
		}
		
		DieRoll thrownRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-100, game.myUI);
		
		if (!thrownRoll.isModifiable()) {
			int thrownNum = thrownRoll.getRoll();
			if (thrownNum == 1) {
				int strikeRoll = rng.nextInt(6)+1;
				UI.messageLog.add(this.toChoiceString() + " is taking a Strength 3 hit with a roll of " + strikeRoll);
				this.moveLeft = 0;
				this.knockDown();
				this.hasShot = true;
				this.hasUsedMagic = true;
				game.myUI.reenableComponents();
				this.takeStrike(3, strikeRoll, doneThrowing);
			}
			else if (thrownNum < 6) {
				this.moveLeft = 0;
				this.hasShot = true;
				this.hasUsedMagic = true;
				
				int workingAttacks = this.getAttacks();
				
				Button refreshThrownEffects = new Button();
				refreshThrownEffects.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						setWoundDice(workingAttacks);
					}
				});
				this.refreshButtons.add(refreshThrownEffects);
				
				this.setWoundDice(0);
			}
			else {
				this.moveLeft = this.moveLeft/10 * this.baseMove; // Hard-coded 10 since all cavalry have this move range, would need to adjust
				this.move = this.baseMove;
			}
			
		}
		// Can use might
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	public boolean isCavalry() {
		// TODO Auto-generated method stub
		return this.hasEquipment(new Horse()) || this.hasEquipment(new ArmoredHorse()) || this.hasEquipment(new Warg());
	}
	
	public Mount getMount() {
		for (Equipment e : this.equipmentList) {
			if (e instanceof Mount)
				return (Mount)e;
		}
		return null;
	}
	
	public void die() {
		game.armies[this.armyIndex].removeUnit(this);
		if (this.battle != null) {
			this.battle.removeUnit(this);
			this.battle = null;
		}
	}
	
	public String toChoiceString() {
		String str = "";
		str += this.name + "-" + this.id;
		return str;
	}
	
	public boolean blocksLOS(Unit looker, Unit target) {
		double theta = Math.atan2(target.y-looker.y, target.x-looker.x);
		double dist = Math.sqrt(Math.pow(target.x-looker.x, 2) + Math.pow(target.y-looker.y, 2));

		// Make an Area representing sight line, clone it for two tests
		Polygon sightTriangle = new Polygon();
		sightTriangle.addPoint(looker.x, looker.y);
		sightTriangle.addPoint((int) (looker.x+dist), looker.y-target.pixelRadius);
		sightTriangle.addPoint((int) (looker.x+dist), looker.y+target.pixelRadius);
		Area sightArea = new Area(sightTriangle);
		AffineTransform rotate = AffineTransform.getRotateInstance(theta, looker.x, looker.y);
		sightArea.transform(rotate);
		
		Area myArea = new Area(new Ellipse2D.Double(this.x-Utils.pixelsPerInch/2, this.y-Utils.pixelsPerInch/2, 
													Utils.pixelsPerInch, Utils.pixelsPerInch));
		
		myArea.intersect(sightArea);
		return !myArea.isEmpty();
	}
	
	public String equipmentString() {
		String str = "";
		if (this.equipmentList.size() == 0)
			return str;
		for (int i = 0; i < this.equipmentList.size(); i++) {
			str += equipmentList.get(i).toString() + ", ";
		}
		return str;
	}
	
	
	public String tabbedStats() {
		String str = "";
		str += this.getFightValue() + "/" + this.getShootValue() + "+    ";
		str += this.getStrength() + "    ";
		str += this.getDefense() + "    ";
		str += this.getAttacks() + "     ";
		str += this.getWounds() + "     ";
		str += this.getCourage();
		return str;
	}
	
	public static String tabbedHeader() {
		return "F/Sv    S    D    A    W    C";
	}
	
	public boolean equals(Object o) {
		if (!(o instanceof Unit)) return false;
		return ((Unit)o).id == this.id;
	}
	
	public int hashCode() {
		return id;
	}
	
	public int getStrength() {
		return workingStrength;
	}
	public int getDefense() {
		return workingDefense;
	}
	public int getCourage() {
		if (this.checkCouragePass())
			return 10;
		return workingCourage;
	}
	public int getAttacks() {
		return workingAttacks;
	}
	public int getWounds() {
		return workingWounds;
	}
	public int getFightValue() {
		if (this.isTransfixed)
			return 1;
		return workingFightValue;
	}
	public int getShootValue() {
		return workingShootValue;
	}
	public int getMight() {
		return mightLeft;
	}
	public int getWill() {
		return willLeft;
	}
	public int getFate() {
		return fateLeft;
	}
	public int getBattleDice() {
		if (this.isTransfixed)
			return 1;
		int bDice = battleDice;
		if (this.battle != null && this.isCavalry() && this.battle.cavalryCharge && this.battle.chargerIndex == this.armyIndex)
			bDice += 1;
		if (this.supporters.size() > 0)
			bDice += 1;
		return bDice;
	}
	public int getBattleBonus() {
		return battleBonus;
	}
	public int getWoundDice() {
		if (this.isTransfixed)
			return 0;
		int wDice = woundDice;
		if (this.battle != null && this.isCavalry() && this.battle.cavalryCharge && this.battle.chargerIndex == this.armyIndex)
			wDice += 1;
		if (this.supporters.size() > 0)
			wDice += 1;
		return wDice;
	}
	public int getWoundBonus() {
		return woundBonus;
	}
	
	
	public void takeWound(int numWounds) {
		this.workingWounds -= numWounds;
	}
	public void healWound(int numWounds) {
		if (this.workingWounds < this.wounds)
			this.workingWounds += 1;
	}
	public void useMight(int mightUsed) {
		this.mightLeft -= mightUsed;
	}
	public void useWill(int willUsed) {
		this.willLeft -= willUsed;
	}
	public void useFate(int fateUsed) {
		this.fateLeft -= fateUsed;
	}
	public boolean canResist() {
		return this.willLeft > 0;
	}
	
	
	public void setStrength(int newStrength){
		this.strength = newStrength;
		this.workingStrength = newStrength;
	}
	public void setDefense(int newDefense){
		this.defense = newDefense;
		this.workingDefense = newDefense;
	}
	public void setCourage(int newCourage){
		this.courage = newCourage;
		this.workingCourage = newCourage;
	}
	public void setAttacks(int newAttacks){
		this.attacks = newAttacks;
		this.workingAttacks = newAttacks;
	}
	public void setWounds(int numWounds) {
		this.wounds = numWounds;
		if (this.workingWounds > this.wounds)
			this.workingWounds = this.wounds;
	}
	public void setFightValue(int newFV){
		this.fightValue = newFV;
		this.workingFightValue = newFV;
	}
	public void setShootValue(int newSV){
		this.shootValue = newSV;
		this.workingShootValue = newSV;
	}
	public void setBattleDice(int bd) {
		this.battleDice = bd;
	}
	public void setBattleBonus(int bb) {
		this.battleBonus = bb;
	}
	public void setWoundDice(int wd) {
		this.woundDice = wd;
	}
	public void setWoundBonus(int wb) {
		this.woundBonus = wb;
	}
	
	public void refresh(){
		if (!layingDown)
			this.moveLeft = this.move;
		else
			this.moveLeft = 1;
		this.hasShot = false;
		this.hasFought = false;
		this.passedChargeTest = false;
		this.passedBrokenTest = false;
		this.tempTerrifying = isTerrifying;
		this.isTransfixed = false;
		this.hasUsedMagic = false;
		this.supporting = null;
		this.supporters = new ArrayList<Unit>();
		this.hasRetreated = true;
		for (Equipment e : this.equipmentList){
			if (e.options != null)
				e.options.select(0);
		}
		for (Button refreshButton : this.refreshButtons) {
			refreshButton.dispatchEvent(new MouseEvent(refreshButton, MouseEvent.MOUSE_CLICKED, 
					System.currentTimeMillis(), 0, 10, 10, 1, false));
		}
		this.refreshButtons.clear();
	}

	public void printInfo() {
		// Print out a garble of info
		System.out.println(this.toChoiceString());
		System.out.println(strength);
		System.out.println("Location: " + this.x + ", " + this.y);
		System.out.println("hasShot/Fought: " + this.hasShot + "/" + this.hasFought);
		if (this.battle != null) {
			System.out.println("Battle: " + this.battle.getClass() + "-" + this.battle);
			System.out.println("   Allies: " + this.battle.getUnitsByIndex(this.armyIndex));
			System.out.println("   Enemies: " + this.battle.getUnitsByIndex((this.armyIndex+1)%2));
		}
		System.out.println("Units contacted: " + this.unitsContacted);
		System.out.println("Terrain contacted: " + this.terrainContacted);
		if (this.supporting == null)
			System.out.print("Supporting/Supporters: null/");
		else
			System.out.print("Supporting/Supporters: " + this.supporting.toChoiceString() + "/");
		System.out.println(this.supporters);
		System.out.println("Is Terrifying: " + this.isTerrifying());
	}



}